﻿/*
 * Cratos Desktop
 * Cratos Collection Proxy class
 * 
 * Copyright (c) 2011-2012 Draco
 * 
 * This file is part of Cratos.
 * 
 * Cratos is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Cratos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cratos.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *       .==.        .==.
 *      //'^\\      //^'\\
 *     // ^ ^\(\__/)/^ ^^\\
 *    //^ ^^ ^/6  6\ ^^ ^ \\
 *   //^ ^^ ^/( .. )\^ ^ ^ \\
 *  // ^^ ^/\| V""V|/\^ ^ ^ \\
 * //^^/\/ /  '~~'  \ \/\^ ^ \\
 *  ------------------------------------
 *  HERE BE DRAGONS
 *  
 *  Johan Dercksen - johan@draco.co.za
 */
using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using Cratos.Tools.General;
using Cratos.Tools.DataObject;
using Cratos.Desktop.CratosWcfService;

namespace Cratos.Desktop
{
	/// <summary>
	/// Cratos Collection Proxy class
	/// </summary>
	public class CratosProxyCollection<T> : CratosProxyBase, ICratosEntityCollectionAccess<T> where T : IDOCratos, new()
	{
		#region Class Constant declarations
		#endregion

		#region Class Event declarations
		#endregion

		#region Class Variable declarations
		private IDOCratosCollection<T> doCollection;
		#endregion

		#region Class Constructors & Destructors
		/// <summary>
		/// Class Constructor
		/// </summary>
		public CratosProxyCollection() : base() { }
		#endregion

		#region Class Properties
		#endregion

		#region Class Methods
		/// <summary>
		/// Entity Perform Action
		/// </summary>
		/// <returns>A Boolean indicating success of the method</returns>
		public bool PerformAction(IDOCratosCollection<T> cratosDOCollection)
		{
			// Declare the required variables
			bool										returnValue = false;
			CratosWcfContract				ctCratos    = null;
			IDOCratosCollection<T>	returnData;

			try
			{
				// Save the incoming data
				this.doCollection = cratosDOCollection;

				// Clear any relevant data
				this.Errors.Clear();
				this.doCollection.Errors.Clear();

				if (this.doCollection.CollectionAction == DOCratosCollectionAction.Retrieve)
				{
					this.doCollection.Clear();
				}

				// Retrieve from the Cache if required
				if (this.doCollection.IsCacheRetrieve || (!this.RetrieveFromCache()))
				{
					// Create and Setup the WCF Contract
					ctCratos              = new CratosWcfContract();
					ctCratos.IsCollection = true;
					ctCratos.IsCompressed = true;
					ctCratos.DODataType   = this.doCollection.GetType().AssemblyQualifiedName;

					if (string.IsNullOrEmpty(this.doCollection.DataObject.DBConnectionName))
					{
						this.doCollection.DataObject.DBConnectionName = DOCratosGlobal.DBConnectionName;
					}

					// Serialize the Data Object
					ctCratos.DOStream = this.doCollection.CreateSerializeStream();

					// Send the request to the server
					ctCratos = CWcfService.PerformAction(ctCratos);

					// Deserialize the relevant object
					returnData = (IDOCratosCollection<T>)DOCratosGlobal.BinDeserialize(ctCratos.DOStream);

					// Process all the Data Objects in the result
					this.doCollection.Clear();
					foreach (T currentObject in returnData) { this.doCollection.Add(currentObject); }

					// Update the relevant properties
					this.doCollection.CollectionAction       = DOCratosCollectionAction.None;
					this.doCollection.CollectionActionResult = returnData.CollectionActionResult;

					// Process the errors returned (If Any)
					foreach (string currentError in ctCratos.Errors)
					{
						this.Errors.Add(new CratosError("EntityAccess", CratosLogSeverity.Exception, currentError));
					}

					// Set the return value
					returnValue = (ctCratos.IsSuccess && (this.Errors.Count <= 0));
				}
				else
				{
					// Update the Collection Action
					this.doCollection.CollectionAction = DOCratosCollectionAction.None;

					// Update the Collection Action Result
					if (this.doCollection.Count > 0) { this.doCollection.CollectionActionResult = DOCratosActionResult.Success; }
					else if (this.doCollection.Errors.Count > 0) { this.doCollection.CollectionActionResult = DOCratosActionResult.Error; }
					else { this.doCollection.CollectionActionResult = DOCratosActionResult.NoRecords; }

					// Set the successful return value
					returnValue = (this.Errors.Count <= 0);
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("CratosProxyCollection.CratosPerformAction", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}
			finally
			{
			}

			// return to calling method
			return (returnValue);
		}
		#endregion

		#region Class Support Methods
		private bool RetrieveFromCache()
		{
			// Declare the required variables
			bool													returnValue = false;
			bool													matchCriteria;
			DOCratosCacheableAttribute[]	cacheAttributes;
			List<IDOCratos>								allItems;
			object												filterValue, compareValue;

			// Determine if we should retrieve from Cache
			if (CWcfService.CachingEnabled)
			{
				// Retrieve the Cacheble attribute
				cacheAttributes = (DOCratosCacheableAttribute[])this.doCollection.GetType().GetCustomAttributes(typeof(DOCratosCacheableAttribute), false);

			  // Make sure the item is Cacheble
			  if (cacheAttributes.Length > 0)
			  {
					// Retrieve the items from the cache
					allItems = CWcfService.Cache.RetrieveItems(this.doCollection.GetType().AssemblyQualifiedName);

					// Query the objects currently in the Cache
					var filteredItems = from qi in allItems select qi;

			    // Handle the Action to be performed
					switch (this.doCollection.CollectionAction)
					{
						case DOCratosCollectionAction.Retrieve:
							#region Retrieve All action
							// Process the Retrieve All Filters
							if (this.doCollection.DataObject.AllDOCollectionFilters.Count > 0)
							{
								// Process all the found items
								foreach (T currentDOItem in filteredItems)
								{
									// Reset the Match Criteria
									matchCriteria = true;

									// Process all the Filter parameters
									foreach (DOCratosCollectionFilterAttribute currentDOFilter in this.doCollection.DataObject.AllDOCollectionFilters)
									{
										// Retrieve the relevant values
										filterValue	 = DOCratosHelper.GetPropertyValue(this.doCollection.DataObject, currentDOFilter.Property);
										compareValue = DOCratosHelper.GetPropertyValue(currentDOItem, currentDOFilter.Property);

										// Compare the values
										if (!DOCratosHelper.CompareValues(filterValue, compareValue, currentDOFilter.DbType,
																											currentDOFilter.IsMandatory, currentDOFilter.IsIgnoreCompareIfNull))
										{
											matchCriteria = false;
											break;
										}
									}

									// Add the item to the finished list
									if (matchCriteria) { this.doCollection.Add(currentDOItem); }
								}

								// Update the successful return value
								returnValue = true;
							}
							else
							{
								// Add the items to the list
								foreach (IDOCratos currentItem in filteredItems) { this.doCollection.Add((T)currentItem); returnValue = true; }
							}
							#endregion

							break;

						case DOCratosCollectionAction.Custom:
							#region Custom action
							//        // Process the Retrieve All Filters
							//        if ((this.DataObjectList.DataObject.GetCustomAction(this.DataObjectList.DOActionName).IsExpectOutput) &&
							//            (this.m_DataObjectList.DataObject.DOCustomColumns.Count > 0))
							//        {
							//          // Process all the found items
							//          foreach (DORaptorBase currentDOItem in filteredItems)
							//          {
							//            // Reset the Match Criteria
							//            matchCriteria = true;

							//            // Process all the Filter parameters
							//            foreach (DORaptorCustomActionAttribute currentDOColumn in this.DataObjectList.DataObject.DOCustomColumns)
							//            {
							//              // Make sure the Custome Name matches
							//              if (currentDOColumn.Name == this.DataObjectList.DOActionName)
							//              {
							//                // Make sure this is an IN or INOUT parameter
							//                if ((currentDOColumn.PropertyDirection == DOActionPropertyDirection.In) ||
							//                    (currentDOColumn.PropertyDirection == DOActionPropertyDirection.InOut))
							//                {
							//                  // Retrieve the relevant values
							//                  filterValue = this.DataObjectList.DataObject.GetType().GetProperty(currentDOColumn.PropertyName).GetValue(this.DataObjectList.DataObject, null);
							//                  compareValue = currentDOItem.GetType().GetProperty(currentDOColumn.PropertyName).GetValue(currentDOItem, null);

							//                  // Compare the values
							//                  if (!DORaptorHelper.CompareValues(filterValue, compareValue, currentDOColumn.DBType,
							//                                                    currentDOColumn.IsInMandatory, currentDOColumn.IsIgnoreCompareIfNull))
							//                  {
							//                    matchCriteria = false;
							//                    break;
							//                  }
							//                }
							//              }
							//            }

							//            // Add the item to the finished list
							//            if (matchCriteria) { this.DataObjectList.Add((T)currentDOItem); }
							//          }
							//        }
							//        else
							//        {
							//          // Add the items to the list
							//          foreach (DORaptorBase currentItem in filteredItems) { this.DataObjectList.Add((T)currentItem); returnValue = true; }
							//        }
							#endregion

							break;
					}
				}
			}

			// Return to calling method
			return (returnValue);
		}
		#endregion
	}
}
